🎖️GitЯра🎖️
Commit bfb66eb988f8259e66ab4adb03dbffb900280d3f
Parents : a31fa28
Author : James Rich <2199651+jamesarich@users.noreply.github.com>
Signature : Signature validation error
Date : 2026-08-11T19:01:32-07:00
Committer : GitHub <noreply@github.com>
Date : 2026-08-12T02:01:32Z
fix(data): stop "1 hour" log retention from wiping the MeshLog table (#6635)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Changes
11 files changed, 276 insertions(+), 15 deletions(-)
Diff
diff --git a/core/data/src/commonMain/kotlin/org/meshtastic/core/data/repository/MeshLogRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/meshtastic/core/data/repository/MeshLogRepositoryImpl.kt
index 1f52fc4c4c..e741485d5b 100644
--- a/core/data/src/commonMain/kotlin/org/meshtastic/core/data/repository/MeshLogRepositoryImpl.kt
+++ b/core/data/src/commonMain/kotlin/org/meshtastic/core/data/repository/MeshLogRepositoryImpl.kt
@@ -36,6 +36,7 @@ import org.meshtastic.core.model.MeshLog
import org.meshtastic.core.repository.MeshLogPrefs
import org.meshtastic.core.repository.MeshLogRepository
import org.meshtastic.core.repository.MeshLogRepository.Companion.DEFAULT_MAX_LOGS
+import org.meshtastic.core.repository.MeshLogRetention
import org.meshtastic.proto.MeshPacket
import org.meshtastic.proto.MyNodeInfo
import org.meshtastic.proto.PortNum
@@ -226,10 +227,14 @@ open class MeshLogRepositoryImpl(
Unit
}
- /** Prunes the log database based on the configured [retentionDays]. */
- @Suppress("MagicNumber")
+ /**
+ * Prunes the log database based on the configured [retentionDays]. The sentinel values are resolved by
+ * [MeshLogRetention], so "never delete" is a no-op and "1 hour" trims to the last hour rather than scaling the
+ * sentinel by days.
+ */
override suspend fun deleteLogsOlderThan(retentionDays: Int) = withContext(dispatchers.io) {
- val cutoffTime = nowMillis - (retentionDays.toLong() * 24 * 60 * 60 * 1000)
+ val window = MeshLogRetention.windowOrNull(retentionDays) ?: return@withContext
+ val cutoffTime = nowMillis - window.inWholeMilliseconds
dbManager.withDb { it.meshLogDao().deleteOlderThan(cutoffTime) }
Unit
}
diff --git a/core/data/src/commonTest/kotlin/org/meshtastic/core/data/repository/CommonMeshLogRepositoryTest.kt b/core/data/src/commonTest/kotlin/org/meshtastic/core/data/repository/CommonMeshLogRepositoryTest.kt
index 9ebe39bc40..c0ca7c1887 100644
--- a/core/data/src/commonTest/kotlin/org/meshtastic/core/data/repository/CommonMeshLogRepositoryTest.kt
+++ b/core/data/src/commonTest/kotlin/org/meshtastic/core/data/repository/CommonMeshLogRepositoryTest.kt
@@ -29,6 +29,7 @@ import org.meshtastic.core.data.datasource.NodeInfoReadDataSource
import org.meshtastic.core.database.entity.MyNodeEntity
import org.meshtastic.core.di.CoroutineDispatchers
import org.meshtastic.core.model.MeshLog
+import org.meshtastic.core.repository.MeshLogRetention
import org.meshtastic.core.testing.FakeDatabaseProvider
import org.meshtastic.core.testing.FakeMeshLogPrefs
import org.meshtastic.proto.Data
@@ -45,6 +46,10 @@ import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
+import kotlin.time.Duration.Companion.days
+import kotlin.time.Duration.Companion.hours
+import kotlin.time.Duration.Companion.minutes
+import org.meshtastic.core.common.util.nowMillis as realNowMillis
abstract class CommonMeshLogRepositoryTest {
@@ -190,6 +195,44 @@ abstract class CommonMeshLogRepositoryTest {
assertEquals(setOf("device", "environment", "local-stats-request"), remainingIds)
}
+ @Test
+ fun `deleteLogsOlderThan one hour sentinel keeps the last hour instead of wiping the table`() =
+ runTest(testDispatcher) {
+ val now = realNowMillis
+ repository.insert(retentionLog("recent", now - 30.minutes.inWholeMilliseconds))
+ repository.insert(retentionLog("stale", now - 2.hours.inWholeMilliseconds))
+
+ repository.deleteLogsOlderThan(MeshLogRetention.ONE_HOUR)
+
+ assertEquals(setOf("recent"), repository.getAllLogsUnbounded().first().map { it.uuid }.toSet())
+ }
+
+ @Test
+ fun `deleteLogsOlderThan keep forever sentinel deletes nothing`() = runTest(testDispatcher) {
+ val now = realNowMillis
+ repository.insert(retentionLog("ancient", now - 400.days.inWholeMilliseconds))
+ repository.insert(retentionLog("recent", now))
+
+ repository.deleteLogsOlderThan(MeshLogRetention.KEEP_FOREVER)
+
+ assertEquals(setOf("ancient", "recent"), repository.getAllLogsUnbounded().first().map { it.uuid }.toSet())
+ }
+
+ @Test
+ fun `deleteLogsOlderThan trims to the configured day count`() = runTest(testDispatcher) {
+ val now = realNowMillis
+ repository.insert(retentionLog("within", now - 6.days.inWholeMilliseconds))
+ repository.insert(retentionLog("outside", now - 8.days.inWholeMilliseconds))
+
+ repository.deleteLogsOlderThan(7)
+
+ assertEquals(setOf("within"), repository.getAllLogsUnbounded().first().map { it.uuid }.toSet())
+ }
+
+ /** Retention is measured against the real clock, so these rows are stamped relative to it. */
+ private fun retentionLog(uuid: String, receivedDate: Long) =
+ MeshLog(uuid = uuid, message_type = "TEXT", received_date = receivedDate, raw_message = "")
+
private fun telemetryLog(
uuid: String,
nodeNum: Int,
diff --git a/core/domain/src/commonTest/kotlin/org/meshtastic/core/domain/usecase/settings/SetMeshLogSettingsUseCaseTest.kt b/core/domain/src/commonTest/kotlin/org/meshtastic/core/domain/usecase/settings/SetMeshLogSettingsUseCaseTest.kt
index 20bf1a13fc..6a30c60967 100644
--- a/core/domain/src/commonTest/kotlin/org/meshtastic/core/domain/usecase/settings/SetMeshLogSettingsUseCaseTest.kt
+++ b/core/domain/src/commonTest/kotlin/org/meshtastic/core/domain/usecase/settings/SetMeshLogSettingsUseCaseTest.kt
@@ -17,11 +17,17 @@
package org.meshtastic.core.domain.usecase.settings
import kotlinx.coroutines.test.runTest
+import org.meshtastic.core.common.util.nowMillis
+import org.meshtastic.core.model.MeshLog
+import org.meshtastic.core.repository.MeshLogRetention
import org.meshtastic.core.testing.FakeMeshLogPrefs
import org.meshtastic.core.testing.FakeMeshLogRepository
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
+import kotlin.time.Duration.Companion.days
+import kotlin.time.Duration.Companion.hours
+import kotlin.time.Duration.Companion.minutes
class SetMeshLogSettingsUseCaseTest {
@@ -43,6 +49,54 @@ class SetMeshLogSettingsUseCaseTest {
assertEquals(365, meshLogRepository.lastDeletedOlderThan)
}
+ @Test
+ fun `setRetentionDays one hour keeps the last hour instead of every log`() = runTest {
+ val now = nowMillis
+ meshLogRepository.setLogs(
+ listOf(
+ MeshLog("recent", "TEXT", now - 30.minutes.inWholeMilliseconds, ""),
+ MeshLog("stale", "TEXT", now - 2.hours.inWholeMilliseconds, ""),
+ ),
+ )
+
+ useCase.setRetentionDays(MeshLogRetention.ONE_HOUR)
+
+ assertEquals(MeshLogRetention.ONE_HOUR, meshLogPrefs.retentionDays.value)
+ assertEquals(listOf("recent"), meshLogRepository.currentLogs.map { it.uuid })
+ }
+
+ @Test
+ fun `setRetentionDays never keeps every log`() = runTest {
+ val now = nowMillis
+ meshLogRepository.setLogs(
+ listOf(
+ MeshLog("ancient", "TEXT", now - 400.days.inWholeMilliseconds, ""),
+ MeshLog("recent", "TEXT", now, ""),
+ ),
+ )
+
+ useCase.setRetentionDays(MeshLogRetention.KEEP_FOREVER)
+
+ assertEquals(MeshLogRetention.KEEP_FOREVER, meshLogPrefs.retentionDays.value)
+ assertEquals(listOf("ancient", "recent"), meshLogRepository.currentLogs.map { it.uuid })
+ }
+
+ @Test
+ fun `setLoggingEnabled true trims to the one hour sentinel`() = runTest {
+ val now = nowMillis
+ meshLogPrefs.setRetentionDays(MeshLogRetention.ONE_HOUR)
+ meshLogRepository.setLogs(
+ listOf(
+ MeshLog("recent", "TEXT", now - 30.minutes.inWholeMilliseconds, ""),
+ MeshLog("stale", "TEXT", now - 2.hours.inWholeMilliseconds, ""),
+ ),
+ )
+
+ useCase.setLoggingEnabled(true)
+
+ assertEquals(listOf("recent"), meshLogRepository.currentLogs.map { it.uuid })
+ }
+
@Test
fun `setLoggingEnabled false deletes all logs`() = runTest {
useCase.setLoggingEnabled(false)
diff --git a/core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/AppPreferences.kt b/core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/AppPreferences.kt
index 278e81cc64..e776c5a2aa 100644
--- a/core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/AppPreferences.kt
+++ b/core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/AppPreferences.kt
@@ -58,7 +58,9 @@ interface MeshLogPrefs {
companion object {
const val DEFAULT_RETENTION_DAYS = 30
- const val MIN_RETENTION_DAYS = -1
+
+ /** The lowest selectable setting is the one-hour sentinel, not a day count. */
+ const val MIN_RETENTION_DAYS = MeshLogRetention.ONE_HOUR
const val MAX_RETENTION_DAYS = 365
}
}
diff --git a/core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/MeshLogRepository.kt b/core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/MeshLogRepository.kt
index e9f2ec80b7..fb70805f52 100644
--- a/core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/MeshLogRepository.kt
+++ b/core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/MeshLogRepository.kt
@@ -76,7 +76,10 @@ interface MeshLogRepository {
/** Deletes only local stats telemetry logs for [nodeNum], preserving other telemetry logs. */
suspend fun deleteLocalStatsLogs(nodeNum: Int)
- /** Prunes the log database based on the configured [retentionDays]. */
+ /**
+ * Prunes the log database based on the configured [retentionDays], which carries the [MeshLogRetention] sentinels:
+ * [MeshLogRetention.KEEP_FOREVER] deletes nothing and [MeshLogRetention.ONE_HOUR] keeps only the last hour.
+ */
suspend fun deleteLogsOlderThan(retentionDays: Int)
companion object {
diff --git a/core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/MeshLogRetention.kt b/core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/MeshLogRetention.kt
new file mode 100644
index 0000000000..42f14cac1d
--- /dev/null
+++ b/core/repository/src/commonMain/kotlin/org/meshtastic/core/repository/MeshLogRetention.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2026 Meshtastic LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.meshtastic.core.repository
+
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.days
+import kotlin.time.Duration.Companion.hours
+
+/**
+ * Decodes [MeshLogPrefs.retentionDays], which overloads two sentinels onto the day count: [KEEP_FOREVER] never prunes
+ * and [ONE_HOUR] keeps only the last hour.
+ *
+ * Both sentinels are real user selections rather than "unset", so pruning callers must resolve the window here instead
+ * of treating the setting as a plain day count.
+ */
+object MeshLogRetention {
+
+ /** Retention setting for "never delete". */
+ const val KEEP_FOREVER: Int = 0
+
+ /** Retention setting for "keep the last hour", which cannot be expressed as a whole number of days. */
+ const val ONE_HOUR: Int = -1
+
+ /** The retention window for [retentionDays], or `null` when logs are never pruned. */
+ fun windowOrNull(retentionDays: Int): Duration? = when {
+ retentionDays == KEEP_FOREVER -> null
+
+ // Every negative value resolves to the one-hour sentinel; scaling one by days would put the cutoff in the
+ // future, matching the whole table.
+ retentionDays < 0 -> 1.hours
+
+ else -> retentionDays.days
+ }
+}
diff --git a/core/repository/src/commonTest/kotlin/org/meshtastic/core/repository/MeshLogRetentionTest.kt b/core/repository/src/commonTest/kotlin/org/meshtastic/core/repository/MeshLogRetentionTest.kt
new file mode 100644
index 0000000000..7f2b7d820f
--- /dev/null
+++ b/core/repository/src/commonTest/kotlin/org/meshtastic/core/repository/MeshLogRetentionTest.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2026 Meshtastic LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package org.meshtastic.core.repository
+
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertNull
+import kotlin.test.assertTrue
+import kotlin.time.Duration.Companion.days
+import kotlin.time.Duration.Companion.hours
+
+class MeshLogRetentionTest {
+
+ @Test
+ fun `one hour sentinel resolves to an hour and not a negative day count`() {
+ assertEquals(1.hours, MeshLogRetention.windowOrNull(MeshLogRetention.ONE_HOUR))
+ }
+
+ @Test
+ fun `keep forever sentinel resolves to no window`() {
+ assertNull(MeshLogRetention.windowOrNull(MeshLogRetention.KEEP_FOREVER))
+ }
+
+ @Test
+ fun `positive settings resolve to that many days`() {
+ assertEquals(1.days, MeshLogRetention.windowOrNull(1))
+ assertEquals(7.days, MeshLogRetention.windowOrNull(7))
+ assertEquals(30.days, MeshLogRetention.windowOrNull(MeshLogPrefs.DEFAULT_RETENTION_DAYS))
+ assertEquals(365.days, MeshLogRetention.windowOrNull(MeshLogPrefs.MAX_RETENTION_DAYS))
+ }
+
+ @Test
+ fun `out of range negative settings still resolve to an hour`() {
+ assertEquals(1.hours, MeshLogRetention.windowOrNull(-2))
+ assertEquals(1.hours, MeshLogRetention.windowOrNull(Int.MIN_VALUE))
+ }
+
+ @Test
+ fun `every window is positive so the cutoff never lands in the future`() {
+ val settings = listOf(Int.MIN_VALUE, -2, MeshLogRetention.ONE_HOUR, 1, 7, 365, Int.MAX_VALUE)
+ settings.forEach { setting ->
+ val window = MeshLogRetention.windowOrNull(setting)
+ assertTrue(window == null || window.isPositive(), "window for $setting was $window")
+ }
+ }
+
+ @Test
+ fun `the lowest selectable setting is the one hour sentinel`() {
+ assertEquals(MeshLogRetention.ONE_HOUR, MeshLogPrefs.MIN_RETENTION_DAYS)
+ }
+}
diff --git a/core/service/src/androidMain/kotlin/org/meshtastic/core/service/worker/MeshLogCleanupWorker.kt b/core/service/src/androidMain/kotlin/org/meshtastic/core/service/worker/MeshLogCleanupWorker.kt
index d1470a05f4..5abf43b54d 100644
--- a/core/service/src/androidMain/kotlin/org/meshtastic/core/service/worker/MeshLogCleanupWorker.kt
+++ b/core/service/src/androidMain/kotlin/org/meshtastic/core/service/worker/MeshLogCleanupWorker.kt
@@ -23,6 +23,7 @@ import co.touchlab.kermit.Logger
import org.koin.android.annotation.KoinWorker
import org.meshtastic.core.repository.MeshLogPrefs
import org.meshtastic.core.repository.MeshLogRepository
+import org.meshtastic.core.repository.MeshLogRetention
@KoinWorker
class MeshLogCleanupWorker(
@@ -35,18 +36,13 @@ class MeshLogCleanupWorker(
@Suppress("TooGenericExceptionCaught")
override suspend fun doWork(): Result = try {
val retentionDays = meshLogPrefs.retentionDays.value
+ val retentionWindow = MeshLogRetention.windowOrNull(retentionDays)
if (!meshLogPrefs.loggingEnabled.value) {
logger.i { "Skipping cleanup because mesh log storage is disabled" }
- } else if (retentionDays == 0) {
+ } else if (retentionWindow == null) {
logger.i { "Skipping cleanup because retention is set to never delete" }
} else {
- val retentionLabel =
- if (retentionDays == -1) {
- "1 hour"
- } else {
- "$retentionDays days"
- }
- logger.d { "Cleaning logs older than $retentionLabel" }
+ logger.d { "Cleaning logs older than $retentionWindow" }
meshLogRepository.deleteLogsOlderThan(retentionDays)
logger.i { "Successfully cleaned old MeshLog entries" }
}
diff --git a/core/testing/src/commonMain/kotlin/org/meshtastic/core/testing/FakeMeshLogRepository.kt b/core/testing/src/commonMain/kotlin/org/meshtastic/core/testing/FakeMeshLogRepository.kt
index a5e1567413..ca699d5456 100644
--- a/core/testing/src/commonMain/kotlin/org/meshtastic/core/testing/FakeMeshLogRepository.kt
+++ b/core/testing/src/commonMain/kotlin/org/meshtastic/core/testing/FakeMeshLogRepository.kt
@@ -19,8 +19,10 @@ package org.meshtastic.core.testing
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.map
+import org.meshtastic.core.common.util.nowMillis
import org.meshtastic.core.model.MeshLog
import org.meshtastic.core.repository.MeshLogRepository
+import org.meshtastic.core.repository.MeshLogRetention
import org.meshtastic.proto.MeshPacket
import org.meshtastic.proto.MyNodeInfo
import org.meshtastic.proto.PortNum
@@ -96,6 +98,9 @@ class FakeMeshLogRepository :
override suspend fun deleteLogsOlderThan(retentionDays: Int) {
lastDeletedOlderThan = retentionDays
+ val window = MeshLogRetention.windowOrNull(retentionDays) ?: return
+ val cutoff = nowMillis - window.inWholeMilliseconds
+ logsFlow.value = logsFlow.value.filter { it.received_date >= cutoff }
}
fun setLogs(logs: List<MeshLog>) {
diff --git a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt
index 2cf8f3b3f7..e48bca9b45 100644
--- a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt
+++ b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/debugging/Debug.kt
@@ -66,6 +66,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.collections.immutable.toImmutableList
import org.jetbrains.compose.resources.pluralStringResource
import org.jetbrains.compose.resources.stringResource
+import org.meshtastic.core.repository.MeshLogRetention
import org.meshtastic.core.resources.Res
import org.meshtastic.core.resources.debug_clear
import org.meshtastic.core.resources.debug_decoded_payload
@@ -237,11 +238,11 @@ private fun DebugLogSettings(viewModel: DebugViewModel) {
) {
@Suppress("MagicNumber")
val retentionItems =
- listOf((-1L) to pluralStringResource(Res.plurals.log_retention_hours, 1, 1)) +
+ listOf(MeshLogRetention.ONE_HOUR.toLong() to pluralStringResource(Res.plurals.log_retention_hours, 1, 1)) +
listOf(1, 3, 7, 14, 30, 60, 90, 180, 365).map { days ->
days.toLong() to pluralStringResource(Res.plurals.log_retention_days_quantity, days, days)
} +
- listOf(0L to stringResource(Res.string.log_retention_never))
+ listOf(MeshLogRetention.KEEP_FOREVER.toLong() to stringResource(Res.string.log_retention_never))
DropDownPreference(
title = stringResource(Res.string.log_retention_days),
enabled = loggingEnabled,
diff --git a/feature/settings/src/commonTest/kotlin/org/meshtastic/feature/settings/debugging/DebugViewModelTest.kt b/feature/settings/src/commonTest/kotlin/org/meshtastic/feature/settings/debugging/DebugViewModelTest.kt
index 8eb9aaec3d..34bfff44e7 100644
--- a/feature/settings/src/commonTest/kotlin/org/meshtastic/feature/settings/debugging/DebugViewModelTest.kt
+++ b/feature/settings/src/commonTest/kotlin/org/meshtastic/feature/settings/debugging/DebugViewModelTest.kt
@@ -29,7 +29,10 @@ import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain
+import org.meshtastic.core.common.util.nowMillis
import org.meshtastic.core.di.CoroutineDispatchers
+import org.meshtastic.core.model.MeshLog
+import org.meshtastic.core.repository.MeshLogRetention
import org.meshtastic.core.testing.FakeMeshLogPrefs
import org.meshtastic.core.testing.FakeMeshLogRepository
import org.meshtastic.core.testing.FakeNodeRepository
@@ -37,6 +40,9 @@ import org.meshtastic.core.ui.util.AlertManager
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Test
+import kotlin.time.Duration.Companion.days
+import kotlin.time.Duration.Companion.hours
+import kotlin.time.Duration.Companion.minutes
@OptIn(ExperimentalCoroutinesApi::class)
class DebugViewModelTest {
@@ -84,6 +90,39 @@ class DebugViewModelTest {
viewModel.retentionDays.value shouldBe 14
}
+ @Test
+ fun `setRetentionDays one hour keeps the last hour instead of clearing the log`() = runTest {
+ val now = nowMillis
+ meshLogRepository.setLogs(
+ listOf(
+ MeshLog("recent", "TEXT", now - 30.minutes.inWholeMilliseconds, ""),
+ MeshLog("stale", "TEXT", now - 2.hours.inWholeMilliseconds, ""),
+ ),
+ )
+
+ viewModel.setRetentionDays(MeshLogRetention.ONE_HOUR)
+
+ meshLogPrefs.retentionDays.value shouldBe MeshLogRetention.ONE_HOUR
+ viewModel.retentionDays.value shouldBe MeshLogRetention.ONE_HOUR
+ meshLogRepository.currentLogs.map { it.uuid } shouldBe listOf("recent")
+ }
+
+ @Test
+ fun `setRetentionDays never keeps every log`() = runTest {
+ val now = nowMillis
+ meshLogRepository.setLogs(
+ listOf(
+ MeshLog("ancient", "TEXT", now - 400.days.inWholeMilliseconds, ""),
+ MeshLog("recent", "TEXT", now, ""),
+ ),
+ )
+
+ viewModel.setRetentionDays(MeshLogRetention.KEEP_FOREVER)
+
+ meshLogPrefs.retentionDays.value shouldBe MeshLogRetention.KEEP_FOREVER
+ meshLogRepository.currentLogs.map { it.uuid } shouldBe listOf("ancient", "recent")
+ }
+
@Test
fun `setLoggingEnabled false deletes all logs`() = runTest {
meshLogRepository.insert(org.meshtastic.core.model.MeshLog("123", "type", 1L, "raw"))
Served by rngit 1.5.2 - Generated in 0.35s